import {
  useLayoutEffect,
  useRef,
  useState,
  type PropsWithChildren,
} from "react";
import useOnMounted from "@/lib/hooks/useOnMounted";
import clsm from "@/lib/utils/clsm";
import useLatestRef from "@/lib/hooks/useLatestRef";

type AutoScrollProps = PropsWithChildren<{
  className?: string;
  speed?: number;
}>;

export default interface InfiniteScroll {
  Item: typeof InfiniteScrollItem;
}
export default function InfiniteScroll(props: AutoScrollProps) {
  const { className, children, speed = 1 } = props;

  const elRef = useRef<HTMLDivElement>(null);
  const widthRef = useRef(0);
  const scrollWidthRef = useRef(0);
  const [offset, setOffset] = useState(0);
  const optionsRef = useLatestRef({ speed });

  useLayoutEffect(() => {
    widthRef.current = elRef.current!.clientWidth;
    scrollWidthRef.current = elRef.current!.scrollWidth;
  }, []);

  useOnMounted(() => {
    let timer: number;

    function tick() {
      setOffset((p) => {
        if (p <= -scrollWidthRef.current) {
          return widthRef.current;
        }
        return p - optionsRef.current.speed;
      });
      timer = requestAnimationFrame(tick);
    }

    if (scrollWidthRef.current > widthRef.current) {
      tick();
    }

    return () => {
      cancelAnimationFrame(timer);
    };
  });

  return (
    <div className={clsm("overflow-hidden", className)} ref={elRef}>
      <div
        style={{
          transform: `translate(${offset}px, 0)`,
        }}
        className="flex overflow-visible"
      >
        {children}
      </div>
    </div>
  );
}

InfiniteScroll.Item = InfiniteScrollItem;

type InfiniteScrollItemProps = PropsWithChildren<{
  className?: string;
}>;
function InfiniteScrollItem(props: InfiniteScrollItemProps) {
  const { children, className } = props;

  return (
    <div
      className={clsm(
        "inline-flex w-full min-w-0 flex-none items-center",
        className,
      )}
    >
      {children}
    </div>
  );
}
